package hypernexusnats

import (
	"fmt"
	"sync"
	"time"

	"github.com/TarsCloud/TarsGo/tars"
	"github.com/TarsCloud/TarsGo/tars/util/conf"

	// 注意：需要添加NATS依赖
	// go get github.com/nats-io/nats.go
	"github.com/nats-io/nats.go"
)

// NatsClient 提供与NATS服务交互的客户端
type NatsClient struct {
	Conn        *nats.Conn
	Subscribers map[string]*nats.Subscription
	mu          sync.RWMutex
}

// Init 初始化NatsClient
func (c *NatsClient) Init(comm *tars.Communicator, sConf *conf.Conf) error {
	// 从配置中获取NATS服务器地址，如果没有配置则使用默认值
	natsURL := sConf.GetStringWithDef("/server<natsServer>", "nats://localhost:4222")

	// 连接选项
	options := []nats.Option{
		nats.Name("HyperNexus-NATS-Client"),
		nats.Timeout(10 * time.Second),
		nats.ReconnectWait(5 * time.Second),
		nats.MaxReconnects(-1), // 无限重连
		nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
			fmt.Printf("NATS连接断开: %v\n", err)
		}),
		nats.ReconnectHandler(func(nc *nats.Conn) {
			fmt.Printf("NATS重新连接到: %s\n", nc.ConnectedUrl())
		}),
		nats.ErrorHandler(func(nc *nats.Conn, sub *nats.Subscription, err error) {
			fmt.Printf("NATS错误: %v\n", err)
		}),
	}

	// 连接到NATS服务器
	nc, err := nats.Connect(natsURL, options...)
	if err != nil {
		return fmt.Errorf("连接NATS服务器失败: %v", err)
	}

	c.Conn = nc
	c.Subscribers = make(map[string]*nats.Subscription)
	return nil
}

// Close 关闭NATS连接
func (c *NatsClient) Close() {
	if c.Conn != nil {
		c.mu.Lock()
		defer c.mu.Unlock()

		// 取消所有订阅
		for _, sub := range c.Subscribers {
			sub.Unsubscribe()
		}

		c.Conn.Close()
	}
}

// Publish 发布消息到指定主题
func (c *NatsClient) Publish(subject string, data []byte) error {
	if c.Conn == nil {
		return fmt.Errorf("NATS客户端未初始化")
	}
	return c.Conn.Publish(subject, data)
}

// PublishWithReply 发布消息并等待回复
func (c *NatsClient) PublishWithReply(subject string, reply string, data []byte) error {
	if c.Conn == nil {
		return fmt.Errorf("NATS客户端未初始化")
	}
	return c.Conn.PublishRequest(subject, reply, data)
}

// Request 发送请求并等待响应
func (c *NatsClient) Request(subject string, data []byte, timeout time.Duration) (*nats.Msg, error) {
	if c.Conn == nil {
		return nil, fmt.Errorf("NATS客户端未初始化")
	}
	return c.Conn.Request(subject, data, timeout)
}

// Subscribe 订阅主题
func (c *NatsClient) Subscribe(subject string, callback nats.MsgHandler) error {
	if c.Conn == nil {
		return fmt.Errorf("NATS客户端未初始化")
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	// 检查是否已经订阅
	if _, exists := c.Subscribers[subject]; exists {
		return fmt.Errorf("已经订阅了主题: %s", subject)
	}

	// 创建新的订阅
	sub, err := c.Conn.Subscribe(subject, callback)
	if err != nil {
		return err
	}

	c.Subscribers[subject] = sub
	return nil
}

// Unsubscribe 取消订阅
func (c *NatsClient) Unsubscribe(subject string) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	sub, exists := c.Subscribers[subject]
	if !exists {
		return fmt.Errorf("未找到主题的订阅: %s", subject)
	}

	err := sub.Unsubscribe()
	if err != nil {
		return err
	}

	delete(c.Subscribers, subject)
	return nil
}

// QueueSubscribe 队列订阅
func (c *NatsClient) QueueSubscribe(subject, queue string, callback nats.MsgHandler) error {
	if c.Conn == nil {
		return fmt.Errorf("NATS客户端未初始化")
	}

	c.mu.Lock()
	defer c.mu.Unlock()

	// 生成唯一的订阅标识符
	subID := fmt.Sprintf("%s:%s", subject, queue)

	// 检查是否已经订阅,如果已经订阅则先取消订阅
	if oldSub, exists := c.Subscribers[subID]; exists {
		tars.GetLogger("").Infof("NATS queue subscription for subject '%s' and queue '%s' already exists. Unsubscribing before creating a new one.", subject, queue)
		if err := oldSub.Unsubscribe(); err != nil {
			// 即使取消订阅失败，也尝试继续，因为新的订阅可能会覆盖旧的
			tars.GetLogger("").Errorf("Error unsubscribing from NATS subject '%s', queue '%s': %v", subject, queue, err)
		}
	}

	// 创建新的队列订阅
	sub, err := c.Conn.QueueSubscribe(subject, queue, callback)
	if err != nil {
		return fmt.Errorf("failed to create NATS queue subscription for subject '%s', queue '%s': %v", subject, queue, err)
	}

	c.Subscribers[subID] = sub
	tars.GetLogger("").Infof("Successfully created NATS queue subscription for subject '%s', queue '%s'", subject, queue)
	return nil
}

// NewNatsClient 创建一个新的NatsClient实例
func NewNatsClient() *NatsClient {
	return &NatsClient{
		Subscribers: make(map[string]*nats.Subscription),
	}
}
